package crawlerTools;
import org.apache.commons.lang.StringUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ganjianwen
 */
public class Request {
    private HttpURLConnection connection;
    private int code;

    public Response sendRequest(String url, String method, String headers, String data, String proxy, String encoding, Integer timeout) throws IOException {
        System.out.println("正在请求url:" + url);
        URL uri = new URL(url);
        method = StringUtils.isNotEmpty(method) ? method : "GET";
        Map<Object, Object> mapHeaders = StringUtils.isNotEmpty(headers) ? JsonMap.jsonToMap(headers) : new HashMap<>(10);
        this.connection = (HttpURLConnection) uri.openConnection();
        this.connection.setDoInput(true);
        this.connection.setDoOutput(true);
        this.connection.setUseCaches(false);
        this.connection.setRequestProperty("Connection", "Keep-Alive");
        this.connection.setRequestProperty("Charset", encoding);
        this.connection.setRequestMethod(method);
        this.connection.setConnectTimeout(timeout * 1000);
        if (proxy != null) {
            this.setProxy(proxy);
        }
        this.setHeaders(mapHeaders);
        if (isFormData(data)) {
            this.sendFormData(data);
        }
        if (isJsonData(data)) {
            this.sendJsonData(data);
        }
        String content = readContent(encoding);
        return new Response(content, this.code, connection.getHeaderFields());
    }

    public Response sendRequest(String url, String method, String headers, String data, String proxy, String encoding) throws IOException {
        return sendRequest(url, method, headers, data, proxy, encoding, 5);
    }

    public Response sendRequest(String url, String method, String headers, String data, String proxy) throws IOException {
        return sendRequest(url, method, headers, data, proxy, "UTF-8");
    }

    public Response sendRequest(String url, String method, String headers, String data) throws IOException {
        return sendRequest(url, method, headers, data, null);
    }

    public Response sendRequest(String url, String method, String headers) throws IOException {
        return sendRequest(url, method, headers, null);
    }

    public Response sendRequest(String url, String method) throws IOException {
        return sendRequest(url, method, null, null);
    }

    public Response sendRequest(String url) throws IOException {
        return sendRequest(url, null);
    }

    public Response get(String url, String headers, String proxy) throws IOException {
        return sendRequest(url, "GET", headers, null, proxy);
    }

    public Response get(String url, String headers) throws IOException {
        return sendRequest(url, "GET", headers);
    }

    public Response get(String url) throws IOException {
        return sendRequest(url);
    }

    public Response post(String url, String headers, String data, String proxy) throws IOException {
        return sendRequest(url, "POST", headers, data, proxy);
    }

    public Response post(String url, String headers, String data) throws IOException {
        return sendRequest(url, "POST", headers, data, null);
    }

    public Response post(String url, String data) throws IOException {
        return sendRequest(url, "POST", null, data, null);
    }

    public void sendFormData(String data) throws IOException {
        this.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
        PrintWriter pw = new PrintWriter(new BufferedOutputStream(connection.getOutputStream()));
        pw.write(data);
        pw.flush();
        pw.close();
    }

    public void sendJsonData(String data) throws IOException {
        this.setContentType("application/json; charset=UTF-8");
        OutputStream out = this.connection.getOutputStream();
        out.write(data.getBytes());
        out.flush();
        out.close();
    }

    public void setHeaders(String key, String value) {
        this.connection.setRequestProperty(key, value);
    }

    public void setContentType(String type) {
        try {
            this.connection.setRequestProperty("Content-Type", type);
        } catch (Exception e) {
            System.out.println(e);
        }

    }

    public void setProxy(String proxy) {
        if (StringUtils.isEmpty(proxy)) {
            return;
        }
        String address = null;
        String port = "80";
        String[] addressPort = proxy.split(":");
        if (addressPort.length < 1) {
            System.out.println("代理地址为空!");
        } else if (addressPort.length < 2) {
            address = addressPort[0];
        } else {
            address = addressPort[0];
            port = addressPort[1];
        }
        if (StringUtils.isNotEmpty(address)) {
            this.connection.setRequestProperty("http.proxyHost", address);
            this.connection.setRequestProperty("http.proxyPort", port);
        }
    }

    public boolean isJsonData(String data) {
        return StringUtils.isNotEmpty(data) && JsonMap.isJsonObject(data);
    }

    public boolean isFormData(String data) {
        return StringUtils.isNotEmpty(data) && data.contains("=");
    }

    public String readContent(String encoding) throws IOException {
        if (this.connection == null) {
            return "无法请求";
        }
        if (this.getResponse() != 200) {
            System.out.println("响应错误,响应码为" + this.code);
            return String.format("{\"code\":%d}", this.code);
        }
        BufferedReader br = new BufferedReader(new InputStreamReader(this.connection.getInputStream(), encoding));
        String line;
        StringBuilder result = new StringBuilder();
        while ((line = br.readLine()) != null) {
            result.append(line).append("\n");
        }
        this.close();
        this.code = 200;
        return result.toString();
    }

    public String getHeaders() {
        if (this.connection == null) {
            return null;
        } else {
            return this.connection.getHeaderFields().toString();
        }
    }

    public void setHeaders(Map<Object, Object> headers) {
        for (Map.Entry<Object, Object> entry : headers.entrySet()) {
            this.connection.setRequestProperty(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
        }
    }

    public int getResponse() {
        try {
            this.code = this.connection.getResponseCode();
        } catch (IOException e) {
            this.code = 404;
        }
        return this.code;
    }

    public void close() {
        if (this.connection != null) {
            this.connection.disconnect();
        }
    }
}
